<?php

namespace App\Models\Cruise;

use App\Models\BaseModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopOrganizationManageModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderModel;
use App\Models\OpenShop\Organization\OpenShopRegionManageMappingModel;
use App\Models\OpenShop\Organization\OpenShopRegionManageModel;
use App\Models\Shop\ShopModel;
use App\Models\Traits\KfSoftDeletes;
use App\Models\Traits\KfUid;
use App\Remote\Rms\RmsUserRemote;
use App\Service\Kms\Home\HomeService;
use App\Service\Kms\Task\UserRoleService;
use Closure;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Carbon;

class CruiseCheckSelfDetailModel extends BaseModel
{
    use KfUid, KfSoftDeletes;

    protected $table    = 'cruise_check_self_detail';
    protected $fillable = [
        'templateType',
        'sysTemplate',
        'shopId',
        'cruiseCheckCompanyId',
        'taskId',
        'date',
        'status',
        'cruiseOrderId',
        'isDeleted',
    ];


    const STATUS_WAIT        = 0;
    const STATUS_FINISH      = 1;
    const STATUS_NOT_PRODUCE = 2;

    const STATUS_TEXT = [
        self::STATUS_WAIT        => '未完成',
        self::STATUS_FINISH      => '已完成',
        self::STATUS_NOT_PRODUCE => '不生产',
    ];

    // 门店自检对应状态
    const STATUS_1        = 1;
    const STATUS_2        = 2;
    const STATUS_3        = 3;
    const STATUS_4        = 4;
    const STATUS_9        = 9;
    const STATUS_10       = 10;
    const NEW_STATUS_TEXT = [
        self::STATUS_1  => "待完成",
        self::STATUS_2  => "今日不生产",
        self::STATUS_3  => "已过期",
        self::STATUS_4  => "待审核",
        self::STATUS_9  => "审核有异常",
        self::STATUS_10 => "审核无异常"
    ];


    /**
     * 商家端自检记录筛选tab对应枚举
     */
    const CUSTOM_STATE_0 = 0;
    const CUSTOM_STATE_1 = 1;
    const CUSTOM_STATE_2 = 2;
    const CUSTOM_STATE_3 = 3;
    const CUSTOM_STATE_4 = 4;
    const CUSTOM_STATE_5 = 5;

    const CUSTOM_STATE_12   = 12;//审核无异常
    const CUSTOM_STATE_13   = 13;//审核有异常
    const CUSTOM_STATE_TEXT = [
        self::CUSTOM_STATE_0  => "全部",
        self::CUSTOM_STATE_1  => "待完成",
        self::CUSTOM_STATE_2  => "未开始",
        self::CUSTOM_STATE_3  => "已提交",
        self::CUSTOM_STATE_4  => "已过期",
        self::CUSTOM_STATE_5  => "异常",
        self::CUSTOM_STATE_12 => '审核无异常',
        self::CUSTOM_STATE_13 => '审核有异常',
    ];

    /**
     * @return HasOne
     */
    public function cruiseCheckCompanyRel(): HasOne
    {
        return $this->hasOne(CruiseCheckCompanyModel::class, "id", "cruiseCheckCompanyId");
    }

    /**
     * @return HasOne
     */
    public function cruiseCheckDetailsRel(): HasOne
    {
        return $this->hasOne(CruiseCheckDetailModel::class, "orderId", "cruiseOrderId");
    }

    /**
     * @return HasOne
     */
    public function cruiseCheckSelfTaskRel(): HasOne
    {
        return $this->hasOne(CruiseCheckSelfTaskModel::class, "id", "taskId");
    }

    /**
     * @return HasOne
     */
    public function cruiseOrderRel(): HasOne
    {
        return $this->hasOne(CruiseOrderModel::class, "id", "cruiseOrderId");
    }

    /**
     * @return hasMany
     */
    public function cruiseOrderProcessRel(): hasMany
    {
        return $this->hasMany(CruiseOrderProcessModel::class, "cruiseOrderId", "cruiseOrderId");
    }

    /**
     * @return HasOne
     */
    public function cruiseOrderInputsRel(): HasOne
    {
        return $this->HasOne(CruiseOrderInputModel::class, "orderId", "cruiseOrderId");
    }

    /**
     * 转换日期
     *
     * @param int $rule
     * @return string
     */
    public function getExecuteDateText(int $rule): string
    {
        $dateDesc = "";
        // 处理时间
        switch ($rule) {
            case CruiseCheckSelfTaskModel::RULE_DAY:
                $dateDesc = $this->createdAt->format("m月d日");
                break;
            case CruiseCheckSelfTaskModel::RULE_WEEK:
                $weekOfMonth = function (int $timestamp) {
                    $date       = Carbon::createFromTimestamp($timestamp);
                    $dayOfMonth = $date->clone()->format("j");
                    $dayOfWeek  = $date->clone()->format("N");
                    return ceil(($dayOfMonth + $dayOfWeek - 1) / 7);
                };
                $dateDesc    = vsprintf("%s第%d周", [
                    $this->createdAt->format("m月"),
                    $weekOfMonth($this->createdAt->timestamp)
                ]);
                break;
            case CruiseCheckSelfTaskModel::RULE_MONTH:
                $dateDesc = $this->createdAt->format("m月");
                break;
        }

        return $dateDesc;
    }

    /**
     * 生成自定义状态
     */
    public function generateCustomState()
    {
        /** @var CruiseOrderModel $order */
        $order = $this->cruiseOrderRel()->first();
        switch ($order->status) {
            //未提交
            case CruiseOrderModel::STATUS_INIT:
            case CruiseOrderModel::STATUS_NOT_SUBMIT:
                if ($this->executeStartTime > time()) {
                    $this->customState = self::CUSTOM_STATE_2;
                } else {
                    if ($this->executeEndTime > time()) {
                        $this->customState = self::CUSTOM_STATE_1;
                    } else {
                        $this->customState = self::CUSTOM_STATE_4;
                    }
                }
                break;
            case CruiseOrderModel::STATUS_EXPIRED:
                $this->customState = self::CUSTOM_STATE_4;
                break;
            case CruiseOrderModel::STATUS_AUDIT_OK:
                $this->customState = self::CUSTOM_STATE_12;
                break;
            case CruiseOrderModel::STATUS_AUDIT_ERROR:
                $this->customState = self::CUSTOM_STATE_13;
                break;
            default:
                $this->customState = self::CUSTOM_STATE_3;
                break;
        }
        //待完成、已提交、未开始、审核有异常、无、过期
        $customStateSortMap = [
            self::CUSTOM_STATE_1  => 1,
            self::CUSTOM_STATE_3  => 2,
            self::CUSTOM_STATE_2  => 3,
            self::CUSTOM_STATE_12 => 4,
            self::CUSTOM_STATE_13 => 5,
            self::CUSTOM_STATE_4  => 6,
        ];
        $this->customStateSort = $customStateSortMap[$this->customState] ?? 0;

        $this->customStateText = self::CUSTOM_STATE_TEXT[$this->customState];
    }

    /**
     * 格式化时间
     */
    public function formatExecuteTime()
    {
        $this->executeStartTimeText = formatDate($this->executeStartTime, "");
        $this->executeEndTimeText   = formatDate($this->executeEndTime, "");
    }

    /**
     * 门店自检表单完成数据回写
     *
     * @param int $cruiseOrderId
     * @throws GuzzleException
     * @throws Exception
     */
    public static function finish(int $cruiseOrderId)
    {
        try {
            // 更新完成状态&完成时间
            self::query()
                ->where('cruiseOrderId', $cruiseOrderId)
                ->update([
                    'status'     => CruiseCheckSelfDetailModel::STATUS_FINISH,
                    'finishTime' => time(),
                ]);

            // 操作记录 - 获取提交人
            $submit = CruiseOrderProcessModel::query()
                                             ->where("cruiseOrderId", $cruiseOrderId)
                                             ->where("step", CruiseOrderProcessModel::PROCESS_SUBMITTED)
                                             ->orderByDesc("id")
                                             ->first();

            // 更新表单提交人数据
            if ($submit) {
                $submitUser = RmsUserRemote::getRmsUserByIds([$submit->createdByUid],
                        ['id', 'username'])[0] ?? [];
                self::query()
                    ->where('cruiseOrderId', $cruiseOrderId)
                    ->update([
                        "submitUid"      => attributeGet($submit, "id", 0),
                        "submitUsername" => attributeGet($submitUser, "username", ""),
                    ]);
            }
        } catch (Exception $exception) {
            logException("更新门店自检表单完成数据失败", $exception, ["cruiseOrderId" => $cruiseOrderId]);
        }
    }

    /**
     * @return HasOne
     */
    public function shopRel(): HasOne
    {
        return $this->hasOne(ShopModel::class, "id", "shopId");
    }

    /**
     * @param int $role
     * @param int $regionSelectionType
     * @param string $region
     * @param string $regionValue
     * @return Builder|mixed
     */
    public static function buildHomeSearchQuery(
        int $role,
        int $regionSelectionType,
        string $region,
        string $regionValue
    ) {
        $query = function ($query) {
            return $query->where("templateType", CruiseTemplateModel::TYPE_8)->where("shopId", 0);
        };
        if ($role == UserRoleService::ROLE_BASE_SUPERVISOR) {
            $signOrder = OpenShopSignOrderModel::query()->whereHas("checkAcceptRel", function ($query) {
                $query->where("managerId", auth()->user()->rmsUserId);
            })->get();
            if ($signOrder->isNotEmpty()) {
                $shopIds = ShopModel::query()
                                    ->whereIn("shopCode", $signOrder->pluck("shopCode")->toArray())
                                    ->pluck("id")
                                    ->toArray();
                if ($shopIds) {
                    $query = function ($query) use ($shopIds) {
                        $query->whereIn("shopId", $shopIds);
                    };
                }
            }
        } else {
            switch ($regionSelectionType) {
                case HomeService::REGION_SELECTION_TYPE_1:
                    $regionRel = attributeGet(
                        OpenShopOrganizationManageModel::allOrganizationManage()->where("name", $region)->first(),
                        "regionRel",
                        collect([])
                    );
                    if (!empty($regionRel->pluck("provinceCode")->toArray())) {
                        $shopIds = ShopModel::query()
                                            ->whereIn("province", $regionRel->pluck("provinceCode")->toArray())
                                            ->pluck("id")
                                            ->toArray();

                        $query = function ($query) use ($shopIds) {
                            return $query->whereIn("shopId", $shopIds);
                        };
                    }
                    break;
                case HomeService::REGION_SELECTION_TYPE_2:
                    $shopIds = ShopModel::query()->where("province", $regionValue)->pluck("id")->toArray();
                    if (!empty($shopIds)) {
                        $query = function ($query) use ($shopIds) {
                            return $query->whereIn("shopId", $shopIds);
                        };
                    }
                    break;
                case HomeService::REGION_SELECTION_TYPE_3:
                    $shopIds = ShopModel::query()->where("city", $regionValue)->pluck("id")->toArray();
                    if (!empty($shopIds)) {
                        $query = function ($query) use ($shopIds) {
                            return $query->whereIn("shopId", $shopIds);
                        };
                    }
                    break;
                case HomeService::REGION_SELECTION_TYPE_4:
                    $provinceCodes = [];
                    $warRegionRow  = OpenShopRegionManageModel::query()
                                                              ->with([
                                                                  "regionMappingRel" => function ($query) {
                                                                      $query->with([
                                                                          "organizationManageRel" => function ($query) {
                                                                              $query->with("regionRel");
                                                                          }
                                                                      ]);
                                                                  }
                                                              ])->where("name", $region)->first();

                    $warRegionRow->regionMappingRel->each(
                        function (OpenShopRegionManageMappingModel $manageMappingModel) use (&$provinceCodes) {
                            $provinceCodes = array_merge(
                                $provinceCodes,
                                $manageMappingModel->organizationManageRel->regionRel->pluck("provinceCode")->toArray()
                            );
                        });

                    if (!empty($provinceCodes)) {
                        $shopIds = ShopModel::query()
                                            ->whereIn("province", $provinceCodes)
                                            ->pluck("id")
                                            ->toArray();

                        $query = function ($query) use ($shopIds) {
                            return $query->whereIn("shopId", $shopIds);
                        };
                    }
                    break;
                case HomeService::REGION_SELECTION_TYPE_0:
                default:
                    $query = null;
                    break;
            }
        }

        return self::query()->when($query, function ($subQuery) use ($query) {
            return $subQuery->where($query);
        });
    }


    /**
     * @param string $startDate
     * @param string $endDate
     * @param array $checkTypes
     * @return Closure
     */
    public static function timeQuery(string $startDate, string $endDate, array $checkTypes = []): Closure
    {
        return function ($query) use ($startDate, $endDate, $checkTypes) {
            $startDateCarbon = Carbon::createFromTimestamp(strtotime($startDate));
            $endDateCarbon   = Carbon::createFromTimestamp(strtotime($endDate));
            // 未传自检类型 默认所有
            $checkTypes = count($checkTypes) ? $checkTypes : [
                CruiseTemplateModel::SYS_TEMPLATE_SELF_OPEN,
                CruiseTemplateModel::SYS_TEMPLATE_SELF_CLOSE,
                CruiseTemplateModel::SYS_TEMPLATE_SELF_WEEK,
                CruiseTemplateModel::SYS_TEMPLATE_SELF_MONTH
            ];

            foreach ($checkTypes as $checkType) {
                switch ($checkType) {
                    case CruiseTemplateModel::SYS_TEMPLATE_SELF_OPEN:
                        $query->orWhere(function ($query) use ($startDateCarbon, $endDateCarbon) {
                            $query->where("sysTemplate", CruiseTemplateModel::SYS_TEMPLATE_SELF_OPEN)
                                  ->where("createdAt", ">", $startDateCarbon->clone()->startOfDay()->timestamp)
                                  ->where("createdAt", "<", $endDateCarbon->clone()->endOfDay()->timestamp);
                        });
                        break;
                    case CruiseTemplateModel::SYS_TEMPLATE_SELF_CLOSE:
                        $query->orWhere(function ($query) use ($startDateCarbon, $endDateCarbon) {
                            $query->where("sysTemplate", CruiseTemplateModel::SYS_TEMPLATE_SELF_CLOSE)
                                  ->where("createdAt", ">", $startDateCarbon->clone()->startOfDay()->timestamp)
                                  ->where("createdAt", "<", $endDateCarbon->clone()->endOfDay()->timestamp);
                        });
                        break;
                    case CruiseTemplateModel::SYS_TEMPLATE_SELF_WEEK:
                        $query->orWhere(function ($query) use ($startDateCarbon, $endDateCarbon) {
                            $query->where("sysTemplate", CruiseTemplateModel::SYS_TEMPLATE_SELF_WEEK)
                                  ->where("createdAt", ">", $startDateCarbon->clone()->startOfWeek()->timestamp)
                                  ->where("createdAt", "<", $endDateCarbon->clone()->endOfWeek()->timestamp);
                        });
                        break;
                    case CruiseTemplateModel::SYS_TEMPLATE_SELF_MONTH:
                        $query->orWhere(function ($query) use ($startDateCarbon, $endDateCarbon) {
                            $query->where("sysTemplate", CruiseTemplateModel::SYS_TEMPLATE_SELF_MONTH)
                                  ->where("createdAt", ">", $startDateCarbon->clone()->startOfMonth()->timestamp)
                                  ->where("createdAt", "<", $endDateCarbon->clone()->endOfMonth()->timestamp);
                        });
                        break;
                }
            }
        };
    }
}
